"""
监控及概览逻辑处理模块

"""

from datetime import date, timedelta, datetime
from pprint import pprint

from flask import g
from peewee import fn
from playhouse.shortcuts import model_to_dict

from models.order import Order
from models.sdn import Vll, LogicPort
from models.work_order import WorkOrder
from utils.controller import GetStatusNew
from models.user import UserLog, UserOrg
from utils.tools import get_time_between
from components.base_log import log_method_call


@log_method_call(action='Retrieve')
def region_vll():
    data = {}
    vlls = Vll.select().where(Vll.sync_status == "2", Vll.is_del == False, Vll.tenant_id << g.org_ids)
    lgs = LogicPort.select().where(LogicPort.sync_status == "2", LogicPort.is_del == False,
                                   LogicPort.tenant_id << g.org_ids)
    infos = [lg.get_standard_obj() for lg in lgs] + [vll.get_standard_obj() for vll in vlls]
    region_vll_count = {}
    region_vll_bandwidth = {}
    for i in infos:
        region_list = i["endpoint_region_name"].split(',')
        bandwidth_list = i["endpoint_show_bandwidth"].split(',') if i["endpoint_show_bandwidth"] else ''
        vll_type = i['type']
        if len(region_list) == len(bandwidth_list):
            for j in range(len(region_list)):
                if region_list[j] in region_vll_count:
                    region_vll_count[region_list[j]] += 1
                else:
                    region_vll_count[region_list[j]] = 1
                # 端口类型的业务没有带宽，不统计该类型业务的带宽
                if vll_type != 'port':
                    if region_list[j] in region_vll_bandwidth:
                        region_vll_bandwidth[region_list[j]] += int(bandwidth_list[j])
                    else:
                        region_vll_bandwidth[region_list[j]] = int(bandwidth_list[j])
    data['region_vll_count'] = [{'region': k, 'vll_count': v} for k, v in region_vll_count.items()]
    data['region_vll_bandwidth'] = [{'region': k, 'bandwidth': v} for k, v in region_vll_bandwidth.items()]
    return data


@log_method_call(action='Retrieve')
def multi_desc_vll():
    data = []
    count = 5
    vlls = Vll.select().where(Vll.tenant_id << g.org_ids,
                              Vll.type == 'multi',
                              Vll.is_del == False, Vll.sync_status == "2", )
    for vll in vlls:
        vll_obj = vll.get_standard_obj()
        vll_obj['endpoint_count'] = len(vll_obj["endpoint_show_name"].split(','))
        data.append(vll_obj)
    data = sorted(data, key=lambda x: x['endpoint_count'], reverse=True)
    if len(data) > count:
        data = data[0:count]
    return {'multi_desc_vll': data}


@log_method_call(action='Retrieve')
def login_logs():
    count_log = g.json.get('count_log') if g.json.get('count') else 5
    count_day = g.json.get('count_day') if g.json.get('count_day') else 30
    data = {'last_member_logs': []}
    user_ids = UserOrg.select().where(UserOrg.org_id << g.real_org_ids)
    log_condition = [UserLog.user_id << [user.user_id for user in user_ids], UserLog.type == 'login']

    # 获取最近访问用户 前提是没有两条日志的时间完全一样
    distinct_condition = (UserLog
                          .select(UserLog.user_id, fn.MAX(UserLog.create_time).alias('time'))
                          .where(*log_condition)
                          .group_by(UserLog.user_id)
                          .order_by(-UserLog.create_time)
                          .limit(count_log))

    in_time = [entry.time for entry in distinct_condition]
    member_logs = (UserLog
                   .select()
                   .where((UserLog.create_time.in_(in_time)) & (UserLog.type == 'login'))
                   .order_by(-UserLog.create_time))

    for log in member_logs:
        data['last_member_logs'].append(model_to_dict(log))

    date_ago = datetime.today() - timedelta(days=count_day - 1)
    data['day_login_count_list'] = {str(date_ago + timedelta(days=i)): 0 for i in range(count_day)}

    # 获取最近count_day天登录日志数量
    day_login_count_list = (UserLog
                            .select(UserLog.create_time.cast('date').alias('day'),
                                    fn.COUNT(UserLog.id).alias('count'))
                            .where(*log_condition, UserLog.create_time > date_ago)
                            .group_by(fn.DATE_FORMAT('day', UserLog.create_time)))

    day_login_count_list = [{'day': entry.day.strftime('%Y-%m-%d'), 'count': entry.count} for entry in
                            day_login_count_list]
    data['day_login_count_list'] = day_login_count_list
    return data


@log_method_call(action='Retrieve')
def work_order():
    data = {}
    condition = [WorkOrder.start_org_id << g.real_org_ids, WorkOrder.type == 'fault']
    # 工单总数
    data['all_count'] = (WorkOrder.select().where(*condition)).count()
    # 工单关单总数量
    data['all_deal_count'] = (WorkOrder.select().where(*condition, WorkOrder.status == 'closed')).count()
    # 本月关单数量
    current_month = date.today().replace(day=1)
    data['month_deal_count'] = (WorkOrder.select().where(*condition,
                                                         WorkOrder.status == 'closed',
                                                         WorkOrder.close_time > current_month)).count()
    # 故障类型数量列表
    work_orders = (WorkOrder.select(WorkOrder.source_type, fn.COUNT(WorkOrder.id).alias('count'))
                   .where(*condition, WorkOrder.type == 'fault')
                   .group_by(WorkOrder.source_type)
                   .order_by(fn.COUNT(WorkOrder.id).desc()))
    data['type_count_list'] = []
    for work_order in work_orders:
        data['type_count_list'].append({'name': work_order.source_type, 'count': work_order.count})
    return data


@log_method_call(action='Retrieve')
def vll_status():
    vlls = Vll.select().where(Vll.tenant_id << g.org_ids,
                              Vll.type << ['d2d', 'd2c', 'c2c'],
                              Vll.is_del == False,
                              Vll.sync_status == "2")
    data = {}
    for vll in vlls:
        vll_obj = vll.get_standard_obj()
        if vll_obj['status'] in data:
            data[vll_obj['status']] += 1
        else:
            data[vll_obj['status']] = 1
    status_show_name = {'wait_create': "待创建", 'creating': "创建中", 'fault': '故障',
                        'failure': "创建失败", 'stopping': "停止中", 'servicing': "运行中", 'wait_delete': "待删除",
                        'deleting': "删除中", 'delete_failure': "删除失败"}
    data = [{'status': status_show_name[k] if k in status_show_name else k, 'count': v} for k, v in data.items()]
    return {'vll_status_count_list': data}


@log_method_call(action='Retrieve')
def vll_city_list():
    vlls = Vll.select().where(Vll.is_del == False, Vll.tenant_id << g.org_ids, Vll.sync_status == '2')
    lgs = LogicPort.select().where(LogicPort.sync_status == "2", LogicPort.is_del == False,
                                   LogicPort.tenant_id << g.org_ids)
    infos = [lg.get_standard_obj() for lg in lgs] + [vll.get_standard_obj() for vll in vlls]
    city_names = [city["endpoint_city_name"] for city in infos]
    city_names = [j for i in city_names if i for j in i.split(',')]
    city_names = list(set(city_names))
    return {'city_list': city_names}


@log_method_call(action='Retrieve')
def fault_day_count():
    count_day = g.json.get('count_day') if g.json.get('count_day') else 7
    date_ago = date.today() - timedelta(count_day - 1)
    data = {str(date_ago + timedelta(days=i)): 0 for i in range(count_day)}
    query = (WorkOrder
             .select(WorkOrder.create_time.alias('day'), fn.Count(WorkOrder.id).alias('count'))
             .where((WorkOrder.start_org << g.real_org_ids) &
                    (WorkOrder.is_del == False) &
                    (WorkOrder.create_time > date_ago) &
                    (WorkOrder.type == 'fault'))
             .group_by(WorkOrder.create_time))
    day_fault_list = [{'day': work.day, 'count': work.count} for work in query]
    for item in day_fault_list:
        data[item['day'].strftime('%Y-%m-%d')] = item['count']
    data = [{'date': k, 'count': v} for k, v in data.items()]
    return data


@log_method_call(action='Retrieve')
def city_traffic():
    """
    开始时间到当前时间
    """

    def gen_end_traffic_dict(traffic):
        end_traffic_dict = {}
        for i in traffic:
            first_key = next(iter(i))
            end_traffic_dict[first_key] = max(int(i[first_key]['input_bps']),
                                              int(i[first_key]['output_bps']))
        return end_traffic_dict

    city = g.json.get('city')
    if not city:
        return []
    start_date = g.json.get('start_date')
    end_date = g.json.get('end_date')
    traffic_type = g.json.get('traffic_type')
    vlls = Vll.select().where(Vll.tenant_id << g.org_ids,
                              Vll.is_del == False,
                              # Vll.endpoint_city_name ** f'%{city}%',
                              Vll.type << ['d2d', 'd2c', 'c2c'],
                              Vll.sync_status == '2')
    time_format = '%Y-%m-%d %H:%M:%S'
    new_start_date = datetime.strptime(start_date, time_format)
    new_end_date = datetime.strptime(end_date, time_format)
    new_start_date = new_start_date.replace(second=0)
    new_end_date = new_end_date.replace(second=0)
    traffic_dict = get_time_between(new_start_date, new_end_date, type='minute')
    for vll in vlls:
        vll_obj = vll.get_standard_obj()
        if vll_obj['endpoint_city_name'] == city:
            a_traffic = GetStatusNew().get_traffic(conditions={'biz_id': int(vll_obj['a_controller_id'])},
                                                   start_date=new_start_date,
                                                   end_date=new_end_date,
                                                   type=traffic_type)
            a_traffic_dict = gen_end_traffic_dict(a_traffic)
            z_traffic = GetStatusNew().get_traffic(conditions={'biz_id': int(vll_obj['z_controller_id'])},
                                                   start_date=new_start_date,
                                                   end_date=new_end_date,
                                                   type=traffic_type)
            z_traffic_dict = gen_end_traffic_dict(z_traffic)
            for k, v in traffic_dict.items():
                traffic_dict[k] = 0
                traffic_dict[k] += max(a_traffic_dict[k] if k in a_traffic_dict else 0,
                                       z_traffic_dict[k] if k in z_traffic_dict else 0)
    traffic_list = [{'time': k, 'traffic': round(v, 2)} for k, v in traffic_dict.items()]
    return traffic_list


@log_method_call(action='Retrieve')
def vll_endpoints():
    conditions = [Vll.tenant_id << g.org_ids, Vll.is_del == False, Vll.sync_status == '2']
    if g.json.get('type'):
        conditions.append([Vll.type in g.json.get('type')])
    if g.json.get('id'):
        conditions.append([Vll.id == g.json.get('id')])
    vlls = Vll.select().where(*conditions)
    vll_endpoint_show_name_list = [vll.get_standard_obj()["endpoint_show_name"] for vll in vlls]
    endpoints = []
    for i in vll_endpoint_show_name_list:
        ends = i.split(',')
        for end in ends:
            if end not in endpoints:
                endpoints.append(end)
    links = []
    if g.json.get('with_link'):
        links = []
        for i in endpoints:
            for j in endpoints:
                if i != j and {"source": j, "target": i} not in links:
                    links.append({'source': i, 'target': j})
    return {"endpoints": endpoints, 'links': links}


@log_method_call(action='Retrieve')
def get_orders():
    condition = [Order.create_by_org_id << g.real_org_ids]
    month_demand_count_list = (Order.select(fn.SUBSTR(Order.create_time, 1, 7).alias('month'),
                                            fn.COUNT(Order.id).alias('count'))
                               .where(*condition)
                               .group_by(fn.SUBSTR(Order.create_time, 1, 7))
                               )
    result = list(month_demand_count_list.dicts())
    data = {"demand_month_count_list": result}
    return data
